#include "ca_config.h"
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "cre.h"
#include "li_vars.h"
#include "RPE.h"

#pragma region ReversePolandExpression

static RE _SE_pats[7] = {NULL};
typedef enum
{
	SE_pat_immediate_number = 0,
	SE_pat_immediate_string,
	SE_pat_function_call,
	SE_pat_variables,
	SE_pat_operators,
	SE_pat_parentheses,
	SE_pat_end_of_line
} _SE_pat_type;

void RPE_init()
{
	if (*_SE_pats)
		return;
	_SE_pats[SE_pat_immediate_string] = fre_compile("^\\s*((r)?['\"])");										   // string
	_SE_pats[SE_pat_immediate_number] = fre_compile("^\\s*(\\d+(\\.\\d*)?([eE][\\+\\-]?\\d+)?|[Tt]rue|[Ff]alse)"); // immediate number
	_SE_pats[SE_pat_function_call] = fre_compile("^\\s*(\\w+)\\s*\\(");											   // function call
	_SE_pats[SE_pat_variables] = fre_compile("^\\s*(\\w+)");													   // variables
	// common operator: !=, ==, >=, <=, &&, ||, !, ^, *, /, %, +, -, >, <,','
	_SE_pats[SE_pat_operators] = fre_compile("^\\s*(!=|==|>=|<=|&&|\\|\\||!|\\^|\\*|/|%|\\+|-|>|<|,|=)");
	_SE_pats[SE_pat_parentheses] = fre_compile("^\\s*([\\(\\)\\[\\]])"); // parentheses (,),[,]
	_SE_pats[SE_pat_end_of_line] = fre_compile("^\\s*$");				 // end of line
}

int fun_caller_adaptive(Fun fun, int numn, RPEVal *vals, RPEVal out_res)
{
	// TODO: call functions from here
	void *f = fun->ref;
	switch (numn)
	{
	case 0:
		if (fun->type)
		{
			out_res->type = VarTypeFloat;
			out_res->val.vf = ((float (*)())(f))();
		}
		else
		{
			out_res->type = VarTypeInt;
			out_res->val.vi = ((int (*)())(f))();
		}
		break;
	case 1:
		if (fun->type)
		{
			out_res->type = VarTypeFloat;
			out_res->val.vf = ((float (*)(int))(f))((*vals)->val.vi);
		}
		else
		{
			out_res->type = VarTypeInt;
			out_res->val.vi = ((int (*)(int))(f))((*vals)->val.vi);
		}
		break;
	case 2:
		if (fun->type)
		{
			out_res->type = VarTypeFloat;
			out_res->val.vf = ((float (*)(int, int))(f))((*vals)->val.vi, vals[1]->val.vi);
		}
		else
		{
			out_res->type = VarTypeInt;
			out_res->val.vi = ((int (*)(int, int))(f))((*vals)->val.vi, vals[1]->val.vi);
		}
		break;
	case 3:
		if (fun->type)
		{
			out_res->type = VarTypeFloat;
			out_res->val.vf = ((float (*)(int, int, int))(f))((*vals)->val.vi, vals[1]->val.vi, vals[2]->val.vi);
		}
		else
		{
			out_res->type = VarTypeInt;
			out_res->val.vi = ((int (*)(int, int, int))(f))((*vals)->val.vi, vals[1]->val.vi, vals[2]->val.vi);
		}
		break;
	case 4:
		if (fun->type)
		{
			out_res->type = VarTypeFloat;
			out_res->val.vf = ((float (*)(int, int, int, int))(f))((*vals)->val.vi, vals[1]->val.vi, vals[2]->val.vi, vals[3]->val.vi);
		}
		else
		{
			out_res->type = VarTypeInt;
			out_res->val.vi = ((int (*)(int, int, int, int))(f))((*vals)->val.vi, vals[1]->val.vi, vals[2]->val.vi, vals[3]->val.vi);
		}
		break;
	default:
		return -1;
	}
	return 0;
}
#pragma region SE_operator_functions

// numn: the number of values inputed
// vals: a pointer to values in stack
// return: statue, -1 if error
typedef int (*RPEFunction)(int numn, RPEVal *vals, RPEVal out_res);

int __operator_assign__(int numn, RPEVal *vals, RPEVal out_res);
int __operator_add__(int numn, RPEVal *vals, RPEVal out_res);
int __operator_minus__(int numn, RPEVal *vals, RPEVal out_res);
int __operator_uminus__(int numn, RPEVal *vals, RPEVal out_res);
int __operator_multiply__(int numn, RPEVal *vals, RPEVal out_res);
int __operator_divide__(int numn, RPEVal *vals, RPEVal out_res);
int __operator_greater__(int numn, RPEVal *vals, RPEVal out_res);
int __operator_lessen__(int numn, RPEVal *vals, RPEVal out_res);
int __operator_equal__(int numn, RPEVal *vals, RPEVal out_res);
int __operator_nequal__(int numn, RPEVal *vals, RPEVal out_res);
int __operator_bigger__(int numn, RPEVal *vals, RPEVal out_res);
int __operator_smaller__(int numn, RPEVal *vals, RPEVal out_res);
int __operator_and__(int numn, RPEVal *vals, RPEVal out_res);
int __operator_or__(int numn, RPEVal *vals, RPEVal out_res);
int __operator_not__(int numn, RPEVal *vals, RPEVal out_res);
int __operator_mod__(int numn, RPEVal *vals, RPEVal out_res);
int __operator_pow__(int numn, RPEVal *vals, RPEVal out_res);
static int __operator_subscribe__(int numn, RPEVal *vals, RPEVal out_res);

#define val0 (vals[0]->type & VarTypeFloat ? vals[0]->val.vf : vals[0]->val.vi)
#define val1 (vals[1]->type & VarTypeFloat ? vals[1]->val.vf : vals[1]->val.vi)

#define OPE(p, c)                                                                        \
	static int __operator_##p##__(int numn, RPEVal *vals, RPEVal out_res)                \
	{                                                                                    \
		if ((vals[0]->type | vals[1]->type) & (VarTypeArray | VartypeStr | VarTypeBool)) \
		{                                                                                \
			return -1;                                                                   \
		}                                                                                \
		if ((vals[0]->type | vals[1]->type) & VarTypeFloat)                              \
		{                                                                                \
			out_res->type = VarTypeFloat;                                                \
			out_res[0].val.vf = val0 c val1;                                             \
		}                                                                                \
		else                                                                             \
		{                                                                                \
			out_res->type = VarTypeInt;                                                  \
			out_res[0].val.vi = vals[0]->val.vi c vals[1]->val.vi;                       \
		}                                                                                \
		return 0;                                                                        \
	}

static int __operator_add__(int numn, RPEVal *vals, RPEVal out_res)
{
	if ((vals[0]->type | vals[1]->type) & (VarTypeArray | VarTypeBool))
	{
		return -1;
	}
	if ((vals[0]->type | vals[1]->type) & VarTypeFloat)
	{
		out_res->type = VarTypeFloat;
		out_res[0].val.vf = val0 + val1;
	}
	else if ((vals[0]->type | vals[1]->type) & VartypeStr)
	{
		if (!((vals[0]->type & vals[1]->type) & VartypeStr))
		{
			return -3;
		}
		int m = strlen(vals[0]->val.vs);
		int n = strlen(vals[1]->val.vs);
		str np = malloc(m + n + 1);
		if (!np)
			return -__LINE__;
		memcpy(np, vals[0]->val.vs, m);
		memcpy(np + m, vals[1]->val.vs, n + 1);
		// vals[0]->val.vs = np;
		out_res->type = VartypeStr | VarTypeTemp;
		out_res->val.vs = np;
	}
	else
	{
		out_res->type = VarTypeInt;
		out_res[0].val.vi = vals[0]->val.vi + vals[1]->val.vi;
	}
	return 0;
}
static int __operator_assign__(int numn, RPEVal *vals, RPEVal out_res)
{
	// TODO: free some object? copy object
	if ((*vals)->type & VarTypeReadOnly)
		return -5;
	(*vals)->type = vals[1]->type & (~VarTypeReadOnly);
	(*vals)->val = vals[1]->val;
	if ((*vals)->type & VarTypePtr)
	{
		*(int *)((*vals)->_ptr) = vals[1]->val.vi;
	}
	(*vals)->len = vals[1]->len;
	out_res->type = (*vals)->type;
	out_res->val = (*vals)->val; // not OK, if the temp var are cleared
	out_res->len = (*vals)->len;
	return 0;
}
static int __operator_uminus__(int numn, RPEVal *vals, RPEVal out_res)
{
	if ((vals[0]->type) & (VarTypeArray | VartypeStr | VarTypeBool))
	{
		return -1;
	}
	if ((vals[0]->type) & VarTypeFloat)
	{
		out_res->type = VarTypeFloat;
		out_res[0].val.vf = -(*vals)->val.vf;
	}
	else
	{
		out_res->type = VarTypeInt;
		out_res[0].val.vi = -(*vals)->val.vi;
	}
	return 0;
}
OPE(minus, -);
OPE(multiply, *);
OPE(divide, /);

#undef OPE
#define OPE(p, c)                                                                        \
	static int __operator_##p##__(int numn, RPEVal *vals, RPEVal out_res)                \
	{                                                                                    \
		if ((vals[0]->type | vals[1]->type) & (VarTypeArray | VartypeStr | VarTypeBool)) \
		{                                                                                \
			return -1;                                                                   \
		}                                                                                \
		out_res->val.vi = val0 c val1;                                                   \
		out_res->type = VarTypeBool;                                                     \
		return 0;                                                                        \
	}
OPE(greater, >=);
OPE(lessen, <=);
OPE(equal, ==);
OPE(nequal, !=);
OPE(bigger, >);
OPE(smaller, <);
#undef OPE
#define OPE(p, c)                                                          \
	static int __operator_##p##__(int numn, RPEVal *vals, RPEVal out_res)  \
	{                                                                      \
		if ((vals[0]->type | vals[1]->type) & (VarTypeArray | VartypeStr)) \
		{                                                                  \
			return -1;                                                     \
		}                                                                  \
		out_res->val.vi = val0 c val1;                                     \
		out_res->type = VarTypeBool;                                       \
		return 0;                                                          \
	}
OPE(and, &&);
OPE(or, ||);

static int __operator_not__(int numn, RPEVal *vals, RPEVal out_res)
{
	if ((vals[0]->type) & (VarTypeArray))
	{
		return -1;
	}
	int res = 0;
	if ((vals[0]->type) & (VartypeStr))
	{
		if (!(*vals)->val.vs)
			res = 1;
		if (!(*((*vals)->val.vs)))
			res = 1;
	}
	if ((vals[0]->type) & (VarTypeBool))
	{
		res = !((*vals)->val.vi);
	}
	else
		res = !val0;
	out_res->type = VarTypeBool;
	out_res->val.vi = res;
	return 0;
}
static int __operator_mod__(int numn, RPEVal *vals, RPEVal out_res)
{
	if ((vals[0]->type) & (VarTypeArray | VartypeStr | VarTypeBool))
	{
		return -1;
	}
	if ((vals[0]->type | vals[1]->type) & VarTypeFloat)
	{
		out_res->type = VarTypeFloat;
		out_res->val.vf = fmodf(val0, val1);
	}
	else
	{
		out_res->type = VarTypeInt;
		out_res->val.vi = vals[0]->val.vi % vals[1]->val.vi;
	}
	return 0;
}

static int __operator_pow__(int numn, RPEVal *vals, RPEVal out_res)
{
	if ((vals[0]->type) & (VarTypeArray | VartypeStr | VarTypeBool))
	{
		return -1;
	}
	if ((vals[0]->type | vals[1]->type) & VarTypeFloat)
	{
		out_res->type = VarTypeFloat;
		out_res->val.vf = powf(val0, val1);
		return 0;
	}
	register int res = 1;
	register int x = (*vals)->val.vi;
	register int n = vals[1]->val.vi;
	if (n >= 0)
	{
		for (; n; n--)
		{
			res *= x;
		}
		out_res->type = VarTypeInt;
		out_res->val.vi = res;
	}
	else
	{
		for (; n; n++)
		{
			res *= x;
		}
		out_res->type = VarTypeFloat;
		out_res->val.vf = 1.0f / res;
	}
	return 0;
}
#pragma region special operator
static int __operator_subscribe__(int numn, RPEVal *vals, RPEVal out_res)
{
	if (!((vals[0]->type) & (VarTypeArray | VartypeStr)))
	{
		return -1;
	}
	if ((vals[1]->type) & (VarTypeArray | VartypeStr | VarTypeBool))
	{
		return -1;
	}
	if (!((*vals)->type & VarTypeArray))
	{
		out_res->type = VartypeStr;
		// TODO: str allocation
		out_res->val.vs = NULL;
		return 0;
	}
	int ind = 0;
	if (vals[1]->type & VarTypeFloat)
	{
		float decimal;
		float integration;
		decimal = modff(vals[1]->val.vf, &integration);
		if (decimal)
			return -2;
		ind = (int)integration;
	}
	else
	{
		ind = vals[1]->val.vi;
	}
	if (ind >= (*vals)->len)
		return -4;
	// #TODO: this cannot return a array however
	out_res->type = (*vals)->type & (~VarTypeArray);
	out_res->val.vi = (*vals)->val.pi[ind];
	out_res->len = (uint32_t)((void *)((*vals)->val.pi + ind));
	out_res->type |= VarTypePtr; // which means Val_t.len is a pointer
	// out_res->hashCode = 0;
	return 0;
}

#pragma endregion

#undef val0
#undef val1
#undef OPE
#pragma endregion

static int _SE_get_operators_priority(const char *ope, int len, RPEOperator operator)
{
#define C2(c1, c2) ((c1 << 8) | (c2))
	const int opes[] = {'+', '-', '*', '/', '^', '%', '>', '<', C2('=', '='), C2('!', '='), C2('>', '='), C2('<', '='), '!', C2('&', '&'), C2('|', '|'), '='};
	//{ "+","-","*","/","^","%",">","<","==","!=",">=","<=","!","&&","||"，'='};
#undef C2
	const char priorities[] = {4, 4, 5, 5, 6, 5, 3, 3, 2, 2, 3, 3, 7, 1, 1, 0};
#define F(ope) __operator_##ope##__
	const void *ope_funs[] = {F(add), F(minus), F(multiply), F(divide), F(pow), F(mod), F(bigger), F(smaller),
							  F(equal), F(nequal), F(greater), F(lessen), F(not ), F(and), F(or), F(assign)};
	const uint32_t associativity = 0b0000100000001001;
	const uint32_t xnary = 0b0000000000001000;
#undef F
	int hs = *ope++;
	len--;
	if (len) // max 2 characters
	{
		hs = (hs << 8) | *ope;
	}

	for (int i = 0; i < sizeof(opes) / sizeof(*opes); i++)
	{
		if (hs == opes[i])
		{
			operator->priority = priorities[i];
			operator->fun = ope_funs[i];
			int mask = 0b1000000000000000 >> i;
			operator->associativity = associativity & mask ? 1 : 0;
			operator->xnary = xnary & mask ? 1 : 2;
			return 0;
		}
	}
	return -1;
}
const str _RPE_operator_to_str(void *f)
{
	const str opes[] = {"+", "-", "*", "/", "^", "%", ">", "<", "==", "!=", ">=", "<=", "!", "&&", "||", "=", "-", "[]"};
#define F(ope) __operator_##ope##__
	const void *ope_funs[] = {F(add), F(minus), F(multiply), F(divide), F(pow), F(mod), F(bigger), F(smaller),
							  F(equal), F(nequal), F(greater), F(lessen), F(not ), F(and), F(or), F(assign), F(uminus), F(subscribe)};
#undef F
	for (int i = 0; i < sizeof(opes) / sizeof(*opes); i++)
	{
		if (f == ope_funs[i])
		{
			return opes[i];
		}
	}
	return "<Operator>";
}
Li_List RPE_compile(const char *exp, int len)
{
	int i;
	int *vec;
	Li_Stack_t sta, stb;
	init_list(&sta, sizeof(RPEItem_t), 4); // store for numbers
	init_list(&stb, sizeof(RPEItem_t), 4); // store for operators
	int lc_n = 0;
	char *s_new = NULL;
	int stack_depth = 0;
	int _vec[4 * 3];
	int needs = 0;
	enum LastType
	{
		LT_number = 1, // 123.4
		LT_var = 2,	   // var
		LT_ope = 4,	   // +-*/^%
		LT_parL = 8,   // (
		LT_braL = 16,  // [
		LT_parR = 32,  // )
		LT_braR = 64,  // ]
		LT_fun = 128,  // f(
		LT_com = 256,  // ,
		LT_string = 512,
		LT_empty = 1024,
	} last_type = LT_empty;
#define assert_LT_is(v)     \
	if (!(last_type & (v))) \
		goto er;

	while (len > 0)
	{
		for (i = 0; i < sizeof(_SE_pats) / sizeof(*_SE_pats); i++)
		{
			vec = fre_search2(_SE_pats[i], exp, len, _vec, sizeof(_vec) / sizeof(*_vec));
			if (vec)
				break;
		}
		if (!vec)
			goto er;
		len -= _RE_GetGroupLen(vec, 0);
		lc_n = _RE_GetGroupLen(vec, 1);
		str tx = exp + vec[2];
		exp += vec[1];
		RPEItem_t sei = {.type = 0};
		RPEItem item;
		int stack_top;
		switch (i)
		{
		case SE_pat_immediate_number: // immediate number
			assert_LT_is(LT_ope | LT_parL | LT_braL | LT_fun | LT_com | LT_empty);
			sei.type = RPETypeImmediateNumber;
			if (toLower(*tx) == 't')
			{
				sei.val.type = VarTypeBool;
				sei.val.val.vi = 1;
			}
			else if (toLower(*tx) == 'f')
			{
				sei.val.type = VarTypeBool;
				sei.val.val.vi = 0;
			}
			else
			{
				char _tx[__BLM];
				if (lc_n > __BLM - 1)
				{
					goto er;
				}
				memcpy(_tx, tx, lc_n);
				_tx[lc_n] = 0;
				tx = _tx;
				if ((vec[4] != vec[5]) || (vec[6] != vec[7]))
				{
					sei.val.type = VarTypeFloat;
					sei.val.val.vf = (float)atof(tx);
				}
				else
				{
					sei.val.type = VarTypeInt;
					sei.val.val.vi = atoi(tx);
				}
			}
			sei.val.type |= VarTypeReadOnly;
			li_add(&sta, sei);
			last_type = LT_number;
			break;
		case SE_pat_immediate_string:
			assert_LT_is(LT_string | LT_ope | LT_parL | LT_braL | LT_fun | LT_com | LT_empty);
			sei.type = RPETypeImmediateNumber;
			if (vec[4] == vec[5])
			{
				int s_len = 0;
				needs = str_translate_get_len(tx, &s_len);
				if (needs < 0)
					goto er;
				s_len--;
				len -= s_len;
				exp += s_len;
				s_new = (char *)malloc(needs);
				if (!s_new)
					goto er;
				needs = str_translate2(tx, s_new);
				if (needs < 0)
				{
					free(s_new);
					s_new = NULL;
					goto er;
				}
			}
			else
			{
				int s_len = 0;
				needs = str_translate_get_len_r(tx + 1, &s_len);
				if (needs < 0)
					goto er;
				s_len--;
				len -= s_len;
				exp += s_len;
				s_new = (char *)malloc(needs);
				if (!s_new)
					goto er;
				needs = str_translate2_r(tx + 1, s_new);
				if (needs < 0)
				{
					free(s_new);
					s_new = NULL;
					goto er;
				}
			}
			if (last_type & LT_string)
			{
				RPEItem last_item = ((RPEItem_t *)((sta).content)) + (sta.count - 1);
				sta.count--;
				str last_s = last_item->val.val.vs;
				int m = strlen(last_s);
				str s_final = malloc(m + needs);
				memcpy(s_final, last_s, m);
				free(last_s);
				memcpy(s_final + m, s_new, needs);
				free(s_new);
				s_new = s_final;
			}
			sei.val.val.vs = s_new;
			s_new = NULL;
			sei.val.type = VartypeStr | VarTypeReadOnly;
			li_add(&sta, sei);

			last_type = LT_number | LT_string;
			break;
		case SE_pat_function_call: // function call
			assert_LT_is(LT_ope | LT_parL | LT_braL | LT_fun | LT_com | LT_empty);
			sei.type = RPETypeEmpty;
			sei.operator.priority = 0;
			li_add(&sta, sei);
			sei.type = RPETypeFunction;
			sei.operator.hashCode = getHashCode(tx, lc_n);
			sei.operator.priority = 8;
			sei.operator.associativity = 1;
			li_add(&stb, sei);
			last_type = LT_fun;
			break;
		case SE_pat_variables: // variables
			assert_LT_is(LT_ope | LT_parL | LT_braL | LT_fun | LT_com | LT_empty);
			sei.type = RPETypeVar;
			sei.val.len = (uint32_t)getHashCode(tx, lc_n);
			li_add(&sta, sei);
			last_type = LT_var;
			break;
		case SE_pat_operators: // common operator:
			if (*tx == ',')
			{
				assert_LT_is(LT_number | LT_var | LT_parR | LT_braR);
				if (!stack_depth)
					goto er;
				// exclude ','
				last_type = LT_com;
				break;
			}
			sei.type = RPETypeOperator;
			if ((last_type & (LT_ope | LT_parL | LT_braL | LT_com | LT_fun | LT_empty)) && (*tx == '+' || *tx == '-'))
			{
				// exclude unary plus
				if (*tx == '+')
					break;
				// unary plus and minus
				sei.operator.priority = 7;
				sei.operator.xnary = 1;
				sei.operator.associativity = 1;
				sei.operator.fun = __operator_uminus__;
				li_add(&stb, sei);
				last_type = LT_ope;
				break;
			}
			assert_LT_is(LT_number | LT_var | LT_parR | LT_braR);
			if (_SE_get_operators_priority(tx, lc_n, &(sei.operator)) < 0)
				goto er;

			last_type = LT_ope;
			if (!stb.count)
			{
				li_add(&stb, sei);
				break;
			}
			item = list_content(&stb, RPEItem_t);
			stack_top = stb.count - 1;
			while (stack_top >= 0)
			{
				if (item[stack_top].type != RPETypeOperator)
				{
					li_add(&stb, sei); // push
					break;
				}
				if (item[stack_top].operator.priority<sei.operator.priority)
				{
					li_add(&stb, sei); // push
					break;
				}
				else if (item[stack_top].operator.priority == sei.operator.priority)
				{
					if (sei.operator.associativity)
					{
						li_add(&stb, sei); // push
						break;
					}
				}
				RPEItem_t empty = {.type = RPETypeEmpty};
				li_add(&sta, empty);
				li_add(&sta, item[stack_top--]); // pop
				stb.count--;
			}
			if (stack_top < 0)
			{
				li_add(&stb, sei); // push
			}
			break;
		case SE_pat_parentheses: // parentheses (,)
			if (*tx == '(')
			{
				assert_LT_is(LT_ope | LT_parL | LT_braL | LT_fun | LT_com | LT_empty);
				sei.type = RPETypeParentheses;
				sei.operator.priority = 8;
				sei.operator.associativity = 1;
				li_add(&stb, sei);
				stack_depth++;
				last_type = LT_parL;
				break;
			}
			if (*tx == '[')
			{
				assert_LT_is(LT_var | LT_parR | LT_braR);
				sei.type = RPETypeOperator | RPETypeBracket;
				sei.operator.priority = 8;
				sei.operator.associativity = 1;
				sei.operator.fun = __operator_subscribe__;
				sei.operator.xnary = 2;
				li_add(&stb, sei);
				stack_depth++;
				last_type = LT_braL;
				break;
			}
			item = list_content(&stb, RPEItem_t);
			stack_top = stb.count - 1;
			stack_depth--;
			if (*tx == ')')
			{
				assert_LT_is(LT_number | LT_var | LT_parR | LT_braR | LT_fun);
				while (stack_top >= 0)
				{
					if (item[stack_top].type == RPETypeParentheses) // '('
						break;
					if (item[stack_top].type == RPETypeFunction) // 'fun('
					{
						li_add(&sta, item[stack_top]);
						break;
					}
					RPEItem_t empty = {.type = RPETypeEmpty};
					li_add(&sta, empty);
					li_add(&sta, item[stack_top--]);
				}
				if (stack_top < 0)
					goto er;
				stb.count = stack_top;
				last_type = LT_parR;
				break;
			}
			assert_LT_is(LT_number | LT_var | LT_parR | LT_braR);
			// if (*tx == ']')
			while (stack_top >= 0)
			{
				if (item[stack_top].type & RPETypeBracket) // '['
				{
					RPEItem_t empty = {.type = RPETypeEmpty};
					li_add(&sta, empty);
					li_add(&sta, item[stack_top]);
					break;
				}
				RPEItem_t empty = {.type = RPETypeEmpty};
				li_add(&sta, empty);
				li_add(&sta, item[stack_top--]);
			}
			if (stack_top < 0)
				goto er;
			stb.count = stack_top;
			last_type = LT_braR;
			break;
		case SE_pat_end_of_line:
			goto exit;
		default:
			goto er;
		}
	}
#undef assert_LT_is
exit:
	if (stb.count)
	{
		RPEItem item = list_content(&stb, RPEItem_t);
		int stack_top = stb.count - 1;
		RPEItem_t empty = {.type = RPETypeEmpty};
		while (stack_top >= 0)
		{
			li_add(&sta, empty);
			li_add(&sta, item[stack_top--]);
		}
	}
	delete_list_t(&stb);
	list_reduction(&sta);
	return copy_list(&sta);
er:
	delete_list_t(&sta);
	delete_list_t(&stb);
	return NULL;
}
Li_List RPE_compile2(const char *exp, int len, Any push_arg_str, Li_List _arg_txt_segment)
{
	int i;
	int *vec;
	Li_Stack_t sta, stb;
	init_list(&sta, sizeof(RPEItem_t), 4); // store for numbers
	init_list(&stb, sizeof(RPEItem_t), 4); // store for operators
	int lc_n = 0;
	int s_new = 0;
	int stack_depth = 0;
	int _vec[4 * 3];
	int needs = 0;
	enum LastType
	{
		LT_number = 1, // 123.4
		LT_var = 2,	   // var
		LT_ope = 4,	   // +-*/^%
		LT_parL = 8,   // (
		LT_braL = 16,  // [
		LT_parR = 32,  // )
		LT_braR = 64,  // ]
		LT_fun = 128,  // f(
		LT_com = 256,  // ,
		LT_string = 512,
		LT_empty = 1024,
	} last_type = LT_empty;
#define assert_LT_is(v)     \
	if (!(last_type & (v))) \
		goto er;

	while (len > 0)
	{
		for (i = 0; i < sizeof(_SE_pats) / sizeof(*_SE_pats); i++)
		{
			vec = fre_search2(_SE_pats[i], exp, len, _vec, sizeof(_vec) / sizeof(*_vec));
			if (vec)
				break;
		}
		if (!vec)
			goto er;
		len -= _RE_GetGroupLen(vec, 0);
		lc_n = _RE_GetGroupLen(vec, 1);
		str tx = exp + vec[2];
		exp += vec[1];
		RPEItem_t sei = {.type = 0};
		RPEItem item;
		int stack_top;
		switch (i)
		{
		case SE_pat_immediate_number: // immediate number
			assert_LT_is(LT_ope | LT_parL | LT_braL | LT_fun | LT_com | LT_empty);
			sei.type = RPETypeImmediateNumber;
			if (toLower(*tx) == 't')
			{
				sei.val.type = VarTypeBool;
				sei.val.val.vi = 1;
			}
			else if (toLower(*tx) == 'f')
			{
				sei.val.type = VarTypeBool;
				sei.val.val.vi = 0;
			}
			else
			{
				char _tx[__BLM];
				if (lc_n > __BLM - 1)
				{
					goto er;
				}
				memcpy(_tx, tx, lc_n);
				_tx[lc_n] = 0;
				tx = _tx;
				if ((vec[4] != vec[5]) || (vec[6] != vec[7]))
				{
					sei.val.type = VarTypeFloat;
					sei.val.val.vf = (float)atof(tx);
				}
				else
				{
					sei.val.type = VarTypeInt;
					sei.val.val.vi = atoi(tx);
				}
			}
			sei.val.type |= VarTypeReadOnly;
			li_add(&sta, sei);
			last_type = LT_number;
			break;
		case SE_pat_immediate_string:
			assert_LT_is(LT_string | LT_ope | LT_parL | LT_braL | LT_fun | LT_com | LT_empty);
			sei.type = RPETypeImmediateNumber;
			if (vec[4] == vec[5])
			{
				int s_len = 0;
				needs = str_translate_get_len(tx, &s_len);
				if (needs < 0)
					goto er;
				s_len--;
				len -= s_len;
				exp += s_len;
				s_new = ((int (*)(Li_List, const str, int))(push_arg_str))(_arg_txt_segment, tx, needs - 1);
				if (s_new < 0)
					goto er;
				needs = str_translate2(tx, list_content(_arg_txt_segment, char) + s_new);
				if (needs < 0)
				{
					_arg_txt_segment->count = s_new;
					s_new = -1;
					goto er;
				}
			}
			else
			{
				int s_len = 0;
				needs = str_translate_get_len_r(tx + 1, &s_len);
				if (needs < 0)
					goto er;
				s_len--;
				len -= s_len;
				exp += s_len;
				// s_new = (char *)malloc(needs);
				s_new = ((int (*)(Li_List, const str, int))(push_arg_str))(_arg_txt_segment, tx, needs - 1);
				if (s_new < 0)
					goto er;
				needs = str_translate2_r(tx + 1, list_content(_arg_txt_segment, char) + s_new);
				if (needs < 0)
				{
					// free(s_new);
					_arg_txt_segment->count = s_new;
					s_new = -1;
					goto er;
				}
			}
			if (last_type & LT_string)
			{
				RPEItem last_item = ((RPEItem_t *)((sta).content)) + (sta.count - 1);
				sta.count--;
				int last_s = last_item->val.val.vi;
				str this_str = list_content(_arg_txt_segment, char) + s_new;
				_arg_txt_segment->count = s_new - 1;
				s_new = ((int (*)(Li_List, const str, int))(push_arg_str))(_arg_txt_segment, this_str, needs - 1);
				// int m = strlen(last_s);
				// str s_final = malloc(m + needs);
				// memcpy(s_final, last_s, m);
				// free(last_s);
				// memcpy(s_final + m, s_new, needs);
				// free(s_new);
				// s_new = s_final;
			}
			sei.val.val.vi = s_new;
			s_new = -1;
			sei.val.type = VartypeStr | VarTypeReadOnly;
			li_add(&sta, sei);

			last_type = LT_number | LT_string;
			break;
		case SE_pat_function_call: // function call
			assert_LT_is(LT_ope | LT_parL | LT_braL | LT_fun | LT_com | LT_empty);
			sei.type = RPETypeEmpty;
			sei.operator.priority = 0;
			li_add(&sta, sei);
			sei.type = RPETypeFunction;
			sei.operator.hashCode = getHashCode(tx, lc_n);
			sei.operator.priority = 8;
			sei.operator.associativity = 1;
			li_add(&stb, sei);
			last_type = LT_fun;
			break;
		case SE_pat_variables: // variables
			assert_LT_is(LT_ope | LT_parL | LT_braL | LT_fun | LT_com | LT_empty);
			sei.type = RPETypeVar;
			sei.val.len = (uint32_t)getHashCode(tx, lc_n);
			li_add(&sta, sei);
			last_type = LT_var;
			break;
		case SE_pat_operators: // common operator:
			if (*tx == ',')
			{
				assert_LT_is(LT_number | LT_var | LT_parR | LT_braR);
				if (!stack_depth)
					goto er;
				// exclude ','
				last_type = LT_com;
				break;
			}
			sei.type = RPETypeOperator;
			if ((last_type & (LT_ope | LT_parL | LT_braL | LT_com | LT_fun | LT_empty)) && (*tx == '+' || *tx == '-'))
			{
				// exclude unary plus
				if (*tx == '+')
					break;
				// unary plus and minus
				sei.operator.priority = 7;
				sei.operator.xnary = 1;
				sei.operator.associativity = 1;
				sei.operator.fun = __operator_uminus__;
				li_add(&stb, sei);
				last_type = LT_ope;
				break;
			}
			assert_LT_is(LT_number | LT_var | LT_parR | LT_braR);
			if (_SE_get_operators_priority(tx, lc_n, &(sei.operator)) < 0)
				goto er;

			last_type = LT_ope;
			if (!stb.count)
			{
				li_add(&stb, sei);
				break;
			}
			item = list_content(&stb, RPEItem_t);
			stack_top = stb.count - 1;
			while (stack_top >= 0)
			{
				if (item[stack_top].type != RPETypeOperator)
				{
					li_add(&stb, sei); // push
					break;
				}
				if (item[stack_top].operator.priority<sei.operator.priority)
				{
					li_add(&stb, sei); // push
					break;
				}
				else if (item[stack_top].operator.priority == sei.operator.priority)
				{
					if (sei.operator.associativity)
					{
						li_add(&stb, sei); // push
						break;
					}
				}
				RPEItem_t empty = {.type = RPETypeEmpty};
				li_add(&sta, empty);
				li_add(&sta, item[stack_top--]); // pop
				stb.count--;
			}
			if (stack_top < 0)
			{
				li_add(&stb, sei); // push
			}
			break;
		case SE_pat_parentheses: // parentheses (,)
			if (*tx == '(')
			{
				assert_LT_is(LT_ope | LT_parL | LT_braL | LT_fun | LT_com | LT_empty);
				sei.type = RPETypeParentheses;
				sei.operator.priority = 8;
				sei.operator.associativity = 1;
				li_add(&stb, sei);
				stack_depth++;
				last_type = LT_parL;
				break;
			}
			if (*tx == '[')
			{
				assert_LT_is(LT_var | LT_parR | LT_braR);
				sei.type = RPETypeOperator | RPETypeBracket;
				sei.operator.priority = 8;
				sei.operator.associativity = 1;
				sei.operator.fun = __operator_subscribe__;
				sei.operator.xnary = 2;
				li_add(&stb, sei);
				stack_depth++;
				last_type = LT_braL;
				break;
			}
			item = list_content(&stb, RPEItem_t);
			stack_top = stb.count - 1;
			stack_depth--;
			if (*tx == ')')
			{
				assert_LT_is(LT_number | LT_var | LT_parR | LT_braR | LT_fun);
				while (stack_top >= 0)
				{
					if (item[stack_top].type == RPETypeParentheses) // '('
						break;
					if (item[stack_top].type == RPETypeFunction) // 'fun('
					{
						li_add(&sta, item[stack_top]);
						break;
					}
					RPEItem_t empty = {.type = RPETypeEmpty};
					li_add(&sta, empty);
					li_add(&sta, item[stack_top--]);
				}
				if (stack_top < 0)
					goto er;
				stb.count = stack_top;
				last_type = LT_parR;
				break;
			}
			assert_LT_is(LT_number | LT_var | LT_parR | LT_braR);
			// if (*tx == ']')
			while (stack_top >= 0)
			{
				if (item[stack_top].type & RPETypeBracket) // '['
				{
					RPEItem_t empty = {.type = RPETypeEmpty};
					li_add(&sta, empty);
					li_add(&sta, item[stack_top]);
					break;
				}
				RPEItem_t empty = {.type = RPETypeEmpty};
				li_add(&sta, empty);
				li_add(&sta, item[stack_top--]);
			}
			if (stack_top < 0)
				goto er;
			stb.count = stack_top;
			last_type = LT_braR;
			break;
		case SE_pat_end_of_line:
			goto exit;
		default:
			goto er;
		}
	}
#undef assert_LT_is
exit:
	if (stb.count)
	{
		RPEItem item = list_content(&stb, RPEItem_t);
		int stack_top = stb.count - 1;
		RPEItem_t empty = {.type = RPETypeEmpty};
		while (stack_top >= 0)
		{
			li_add(&sta, empty);
			li_add(&sta, item[stack_top--]);
		}
	}
	delete_list_t(&stb);
	list_reduction(&sta);
	return copy_list(&sta);
er:
	delete_list_t(&sta);
	delete_list_t(&stb);
	return NULL;
}

Li_List RPE_compress(Li_List rpe)
{
	int n = rpe->count;
	if (n <= 0)
		return NULL;
	RPEItem item = list_content(rpe, RPEItem_t);
	Li_List types = new_li(int8_t);
	Li_List data = new_li(Any);
	uint8_t rpec_type = 0;
	int8_t empty_flags = -1;
	int8_t *ptr_data = NULL;
	int item_count = 0;
	for (int i = 0; i < n; i++)
	{
		int ope_type = item[i].type;
		RPEItem block = item + i;
		if (ope_type == RPETypeEmpty)
		{
			rpec_type = RPECEmpty;
			li_add(types, rpec_type);
			continue;
		}
		if (ope_type & RPETypeImmediateNumber) // instant number
		{
			rpec_type = RPECNumber | ((block->val.type) & 0x0f);
			li_add(types, rpec_type);

			li_add(data, block->val.val);
			continue;
		}
		if (ope_type & RPETypeVar) // var
		{
			rpec_type = RPECVar;
			li_add(types, rpec_type);
			li_add(data, block->val.len); // or hashCode
			continue;
		}
		if (ope_type & RPETypeOperator)
		{
			types->count--;
			rpec_type = RPECOperator;
			li_add(data, block->operator.fun);
			int xnary = block->operator.xnary;
			if (xnary == 1)
				rpec_type |= RPECOperatorUnary;
			li_add(types, rpec_type);
			continue;
		}

		if (ope_type & RPETypeFunction)
		{
			rpec_type = RPECFun;
			li_add(types, rpec_type);

			li_add(data, block->operator.hashCode);
			continue;
		}
		else
			goto er;
	}
	// fill the padding
	n = types->count;
	item_count = n;
	while (n & (sizeof(Any) - 1))
	{
		n++;
		li_add(types, empty_flags);
	}
	n = data->count;
	n *= sizeof(Any);
	ptr_data = (int8_t *)list_content(data, Any);
	if (list_recap(types, types->count + n) < 0)
		goto er;
	memcpy(list_content(types, int8_t) + types->count, ptr_data, n);
	types->count += n;
	delete_list(data);
	types->cap = item_count;
	return types;
er:
	if (types)
		delete_list(types);
	if (data)
		delete_list(data);
	return NULL;
}
int RPE_execute(Li_List rpe, void *vars, void *funs, void *call_arg, RPEVal out_res, void *stack_heap)
{
	int n = rpe->count;
	if (n <= 0)
		return -1;
	RPEVal *_stackTop = stack_heap;
	int _stack_count = 0;
	RPEItem item = list_content(rpe, RPEItem_t);
	// int last_empty_index = -1;
	for (int i = 0; i < n; i++)
	{
		int ope_type = item[i].type;
		RPEItem block = item + i;
		if (ope_type == RPETypeEmpty)
		{
			// last_empty_index = _stack_count;
			block->val.type = 0;
			_stackTop[_stack_count++] = &(block->val);
			continue;
		}
		if (ope_type & RPETypeImmediateNumber) // instant number
		{
			_stackTop[_stack_count++] = &(block->val);
			continue;
		}
		if (ope_type & RPETypeVar) // var
		{
			Var var = ((Var(*)(void *, HASH))(vars))(call_arg, block->val.len);
			if (!var)
				goto er;
			_stackTop[_stack_count++] = &(var->val_t); // the space, which block lay, is actually unused anymore
			continue;
		}

		if (ope_type & RPETypeOperator)
		{
			RPEVal *vals = _stackTop;
			RPEVal res = vals[_stack_count - 1];
			_stack_count--;
			// a,b,[empty]
			int xnary = block->operator.xnary;
			_stack_count -= xnary;
			vals += _stack_count;
			RPEFunction f = block->operator.fun;
			int ok = f(xnary, vals, res); //&(block->val)
			if (ok < 0)
				goto er;
			_stackTop[_stack_count++] = res; //&(block->val);
			continue;
		}

		if (ope_type & RPETypeFunction)
		{
			// int ind = searchObj3_t(funs, block->operator.hashCode);
			// if (ind < 0)
			//	goto er;
			// Fun fun = list_content(funs, Fun_t) + ind;
			Fun fun = ((Fun(*)(void *, HASH))(funs))(call_arg, block->operator.hashCode);
			if (!fun)
				goto er;
			RPEVal *vals = _stackTop;
			int i = _stack_count - 1; // last_empty_index
			while (i >= 0 && (vals[i]->type))
			{
				i--;
			}
			if (i < 0)
				goto er;
			// last_empty_index = -1;
			RPEVal res = vals[i];
			int ok = fun_caller_adaptive(fun, _stack_count - i - 1, vals + i + 1, res); //&(block->val)
			if (ok < 0)
				goto er;
			// vals[i++] = &(block->val);
			_stack_count = i + 1;
			continue;
		}
		else
			goto er;
	}
	if (_stack_count != 1)
	{
		goto er;
	}
	*out_res = *(_stackTop[0]);
	return 0;
er:
	return -1;
}

int RPE_execute_from_compact(int item_count, int8_t *types, void *vars, void *funs, void *call_arg, RPEVal out_res, void *stack_heap, const str text_segment)
{
	int n = item_count;
	int er_code = RPEE_unexpected_error;
	if (n <= 0)
		return RPEE_empty_input;
	Any *data = NULL;
	if (n & (sizeof(Any) - 1))
	{
		data = (int *)(types + (n & (~(sizeof(Any) - 1))) + sizeof(Any));
	}
	else
	{
		data = (int *)(types + n);
	}

	typedef struct
	{
		int is_entry;
		union
		{
			RPEVal_t val;
			RPEVal p_val;
		};
	} RPESItem_t;
	typedef RPESItem_t *RPESItem;

	RPESItem _stackTop = stack_heap;
	int _stack_count = 0;
	RPEVal_t val;
	RPESItem_t s_val;
	for (int i = 0; i < n; i++)
	{
		int ope_type = (types[i]) & 0x70;
		if (ope_type == RPECEmpty)
		{
			// val.type = 0;
			_stackTop[_stack_count].is_entry = 1;
			_stackTop[_stack_count++].val.type = 0;
			continue;
		}
		if (ope_type == RPECNumber) // instant number
		{
			_stackTop[_stack_count].is_entry = 1;
			VarType vt = (types[i] & 0xf) | VarTypeReadOnly;
			_stackTop[_stack_count].val.type = vt;
			if (!(vt & VartypeStr))
				_stackTop[_stack_count++].val.val = *(CVal *)data++;
			else
			{
				CVal cv = *(CVal *)data++;
				_stackTop[_stack_count++].val.val.vs = cv.vi + text_segment;
			}
			continue;
		}
		if (ope_type == RPECVar) // var
		{
			Var var = ((Var(*)(void *, HASH))(vars))(call_arg, *(HASH *)data++);
			if (!var)
			{
				er_code = RPEE_variable_not_found;
				goto er;
			}
			_stackTop[_stack_count].is_entry = 0;
			_stackTop[_stack_count++].p_val = &(var->val_t);
			continue;
		}

		if (ope_type == RPECOperator)
		{
			_stack_count++;
			RPESItem vals = _stackTop;
			RPEVal *ptr_to_vals = (RPEVal *)(_stackTop + _stack_count);
			RPESItem res = vals + _stack_count - 1;
			_stack_count--;
			RPEFunction f = *(RPEFunction *)data++;
			int xnary = 2;
			if (types[i] & RPECOperatorUnary)
				xnary = 1;
			_stack_count -= xnary;
			vals += _stack_count;
			for (int j = 0; j < xnary; j++)
			{
				ptr_to_vals[j] = vals[j].is_entry ? &(vals[j].val) : vals[j].p_val;
			}
			int ok = f(xnary, ptr_to_vals, &(res->val));
			// clear
			for (int j = 0; j < xnary; j++)
			{
				if ((ptr_to_vals[j]->type) & VarTypeTemp)
				{
					ptr_to_vals[j]->type &= (~VarTypeTemp);
					free(ptr_to_vals[j]->val.pvoid);
					ptr_to_vals[j]->val.pvoid = NULL;
				}
			}
			if (ok < 0)
			{
				goto er;
			}
			res->is_entry = 1;
			_stackTop[_stack_count++] = *res;
			continue;
		}
		if (ope_type == RPECFun)
		{
			Fun fun = ((Fun(*)(void *, HASH))(funs))(call_arg, *(HASH *)data++);
			if (!fun)
				goto er;
			RPEVal *ptr_to_vals = (RPEVal *)(_stackTop + _stack_count);
			RPESItem vals = _stackTop;
			int i = _stack_count - 1; // last_empty_index
			while (i >= 0 && (vals[i].val.type))
			{
				i--;
			}
			if (i < 0)
				goto er;
			RPESItem res = vals + i;
			int xnary = _stack_count - i - 1;
			vals += i + 1;
			for (int j = 0; j < xnary; j++)
			{
				ptr_to_vals[j] = vals[j].is_entry ? &(vals[j].val) : vals[j].p_val;
			}
			int ok = fun_caller_adaptive(fun, xnary, ptr_to_vals, &(res->val)); //&(block->val)
			// clear
			for (int j = 0; j < xnary; j++)
			{
				if ((ptr_to_vals[j]->type) & VarTypeTemp)
				{
					ptr_to_vals[j]->type &= (~VarTypeTemp);
					free(ptr_to_vals[j]->val.pvoid);
					ptr_to_vals[j]->val.pvoid = NULL;
				}
			}
			if (ok < 0)
				goto er;
			_stack_count = i + 1;
			continue;
		}
		else
			goto er;
	}
	if (_stack_count != 1)
	{
		er_code = RPEE_invalid_expression;
		goto er;
	}
	*out_res = _stackTop[0].is_entry ? _stackTop[0].val : *(_stackTop[0].p_val);
	return 0;
er:
	for (int i = 0; i < _stack_count; i++)
	{
		if (!(_stackTop[i].is_entry))
			continue;
		if ((_stackTop[i].val.type) & VarTypeTemp)
		{
			if (_stackTop[i].val.val.pvoid)
				free(_stackTop[i].val.val.pvoid);
		}
	}
	return er_code;
}

int RPE_compile_get_len(const char *exp, int len)
{
	int i;
	int *vec;
	int _vec[4 * 3];
	int stack_depth = 0;
	int needs = 0;
	enum LastType
	{
		LT_number = 1, // 123.4
		LT_var = 2,	   // var
		LT_ope = 4,	   // +-*/^%
		LT_parL = 8,   // (
		LT_braL = 16,  // [
		LT_parR = 32,  // )
		LT_braR = 64,  // ]
		LT_fun = 128,  // f(
		LT_com = 256,  // ,
		LT_string = 512,
		LT_empty = 1024,
	} last_type = LT_empty;
#define assert_LT_is(v)     \
	if (!(last_type & (v))) \
		goto er;

	while (len > 0)
	{
		for (i = 0; i < sizeof(_SE_pats) / sizeof(*_SE_pats); i++)
		{
			vec = fre_search2(_SE_pats[i], exp, len, _vec, sizeof(_vec) / sizeof(*_vec));
			if (vec)
				break;
		}
		if (!vec)
			goto er;
		str tx = exp + vec[2];
		exp += vec[1];
		len -= vec[1];
		switch (i)
		{
		case SE_pat_immediate_number: // immediate number
			assert_LT_is(LT_ope | LT_parL | LT_braL | LT_fun | LT_com | LT_empty);
			last_type = LT_number;
			break;
		case SE_pat_immediate_string:
			assert_LT_is(LT_string | LT_ope | LT_parL | LT_braL | LT_fun | LT_com | LT_empty);
			if (vec[4] == vec[5])
			{
				int s_len = 0;
				needs = str_translate_get_len(tx, &s_len);
				if (needs < 0)
					goto er;
				s_len--;
				len -= s_len;
				exp += s_len;
			}
			else
			{
				int s_len = 0;
				needs = str_translate_get_len_r(tx + 1, &s_len);
				if (needs < 0)
					goto er;
				s_len--;
				len -= s_len;
				exp += s_len;
			}
			last_type = LT_number | LT_string;
			break;
		case SE_pat_function_call: // function call
			assert_LT_is(LT_ope | LT_parL | LT_braL | LT_fun | LT_com | LT_empty);
			last_type = LT_fun;
			break;
		case SE_pat_variables: // variables
			assert_LT_is(LT_ope | LT_parL | LT_braL | LT_fun | LT_com | LT_empty);
			last_type = LT_var;
			break;
		case SE_pat_operators: // common operator:
			if (*tx == ',')
			{
				assert_LT_is(LT_number | LT_var | LT_parR | LT_braR);
				if (!stack_depth)
				{
					return len;
				}
				// exclude ','
				last_type = LT_com;
				break;
			}
			if ((last_type & (LT_ope | LT_parL | LT_braL | LT_com | LT_fun | LT_empty)) && (*tx == '+' || *tx == '-'))
			{
				// exclude unary plus
				if (*tx == '+')
				{
					last_type = LT_ope;
					break;
				}
				last_type = LT_ope;
				break;
			}
			assert_LT_is(LT_number | LT_var | LT_parR | LT_braR);
			last_type = LT_ope;
			break;
		case SE_pat_parentheses: // parentheses (,)
			if (*tx == '(')
			{
				assert_LT_is(LT_ope | LT_parL | LT_braL | LT_fun | LT_com | LT_empty);
				stack_depth++;
				last_type = LT_parL;
				break;
			}
			if (*tx == '[')
			{
				assert_LT_is(LT_var | LT_parR | LT_braR);
				stack_depth++;
				last_type = LT_braL;
				break;
			}
			stack_depth--;
			if (*tx == ')')
			{
				assert_LT_is(LT_number | LT_var | LT_parR | LT_braR | LT_fun);
				last_type = LT_parR;
				break;
			}
			assert_LT_is(LT_number | LT_var | LT_parR | LT_braR);
			// if (*tx == ']')
			last_type = LT_braR;
			break;
		case SE_pat_end_of_line:
			goto exit;
		default:
			goto er;
		}
	}
#undef assert_LT_is
exit:
	return len;
er:
	return -1;
}

#pragma endregion

#pragma region TestSuit
// #define testSuit 1
#if testSuit == 1
#include <stdio.h>

static Var __find_var(void *envs, HASH hs)
{
	int p0 = ((int *)(envs))[0];
	Li_List vars = (Li_List)p0;
	int ind = searchObj3_t(vars, hs);
	if (ind < 0)
		return NULL;
	return list_content(vars, Var_t) + ind;
}
static Fun __find_fun(void *envs, HASH hs)
{
	int p1 = ((int *)(envs))[1];
	Li_List funs = (Li_List)p1;
	int ind = searchObj3_t(funs, hs);
	if (ind < 0)
		return NULL;
	return list_content(funs, Fun_t) + ind;
}

int main(int n, char *args[])
{
	static char tx[256];
	Li_List vars = new_li(Var_t);
	Li_List funs = new_li(Fun_t);
	Var_t var1 = {.name = "a", .type = VarTypeInt, .val = {.vi = 12}};
	addToVar(vars, &var1);
	var1.name = "b";
	var1.type = VarTypeFloat;
	var1.val.vf = 11.0f;
	addToVar(vars, &var1);

	var1.name = "c";
	var1.type = VarTypeFloat | VarTypeArray;
	static float cs[16] = {1., 2., 3., 4.};
	var1.val.pf = cs;
	var1.len = 16;
	addToVar(vars, &var1);

	Fun_t fun = {.name = "sin", .type = 1, .ref = sinf};
	addToFun(funs, &fun);
	fun.name = "cos";
	fun.ref = cosf;
	addToFun(funs, &fun);
	fun.name = "tan";
	fun.ref = tanf;
	addToFun(funs, &fun);
	fun.name = "lg";
	fun.ref = log10f;
	addToFun(funs, &fun);
	fun.name = "exp";
	fun.ref = expf;
	addToFun(funs, &fun);

	int _stackHeap[32];
	Any ps[2] = {vars, funs};
	while (1)
	{
		putchar('>');
		gets_s(tx, sizeof(tx));
		RPE_init();
		Li_List bs = RPE_compile(tx, strlen(tx));
		if (!bs)
		{
			puts("compile error\a");
			continue;
		}
		RPEVal_t res;
		int ok = RPE_execute(bs, __find_var, __find_fun, ps, &res, _stackHeap);
		if (ok < 0)
			return ok;
		if (res.type & VarTypeFloat)
		{
			printf("ans=%f\n", res.val.vf);
		}
		else if (res.type & VarTypeInt)
		{
			printf("ans=%d\n", res.val.vi);
		}
		else if (res.type & VartypeStr)
		{
			printf("ans='%s'\n", res.val.vs);
		}
		else
			return -1;
		Li_List cbs = RPE_compress(bs);
		if (!cbs)
			return -2;
		ok = RPE_execute_from_compact(bs->count, cbs, __find_var, __find_fun, ps, &res, _stackHeap);
		if (ok < 0)
			return ok;
		if (res.type & VarTypeFloat)
		{
			printf("ans=%f\n", res.val.vf);
		}
		else if (res.type & VarTypeInt)
		{
			printf("ans=%d\n", res.val.vi);
		}
		else if (res.type & VartypeStr)
		{
			printf("ans='%s'\n", res.val.vs);
		}
		else
			return -1;
		delete_list(bs);
		delete_list(cbs);
	}
	return 0;
}
#endif
#pragma endregion